// Copyright (c) 2008, 
// Marc Speck, http://www.faindu.com
// All Rights Reserved. The following is Source Code and is subject to all restrictions 
// on such code as contained in the license accompanying this product.
package com.faindu.editImage.base
{

import com.faindu.editImage.EditImage;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;

/**
 * Base class for all controls. A control is user visible element that
 * she can drag to edit the image.
 */
public class BaseControl extends Sprite
{
	/**
	 * Constructor
	 */	
	public function BaseControl( interactionMethod:Function, referenceName:String ) 
	{
		this.interactionMethod = interactionMethod
		this.referenceName = referenceName
	}

	//--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------			
	/**
	 * Interaction method that is called when the user drags the control.
	 * This is for example CropTool.cropLeftInteraction().
	 * 
	 * @see com.faindu.editImage.crop.CropTool.cropLeftInteraction()
	 */
	public var interactionMethod:Function

	/**
	 * The reference name such as "topLeft" or "move".
	 * 
	 * @see com.faindu.editImage.base.BaseTool.TOP_LEFT
	 */
	public var referenceName:String
	
	/**
	 * Cursor belonging to this control
	 */
	protected var cursor: BaseCursor
	
	//----------------------------------
	//  editImage
	//----------------------------------	
	/**
	 * Reference to TransformTool instance using the control.
	 * 
	 * This property is defined after using TransformTool.addControl
	 * prior to being added to the TransformTool display list
	 * (it can be accessed after the TransformTool.CONTROL_INIT event)
	 */
	protected var editImage:EditImage

	//--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------			
	/**
	 * Initiate the control.
	 */
	public function init( editImage:EditImage, startInteractionHandler:Function, tool:Sprite ): void 
	{
		this.editImage = editImage
		addEventListener( MouseEvent.MOUSE_DOWN, startInteractionHandler )
		tool.addChild( this )
		
		// show and hide cursor for control
		addEventListener( MouseEvent.MOUSE_OVER, showCursor )
		addEventListener( MouseEvent.MOUSE_OUT, hideCursor )
		
		editImage.addEventListener( EditImageEvent.CONTROL_MOVE, controlMouseMove )

		if ( cursor )
		{
			cursor.visible = false
			addChild( cursor )
		}		
		
		draw()
	}
	
	/**
	 * Show the cursor of this control.
	 */
	protected function showCursor( mouseEvent:MouseEvent ): void
	{
		if ( cursor )
		{
			moveCursor( mouseEvent )
			cursor.visible = true
			addEventListener( MouseEvent.MOUSE_MOVE, moveCursor )
		}
	}

	/**
	 * Hide the cursor of this control.
	 */	
	protected function hideCursor( mouseEvent:MouseEvent ): void
	{
		if ( cursor )
		{
			cursor.visible = false
			removeEventListener( MouseEvent.MOUSE_MOVE, moveCursor )
		}
	}
	
	/**
	 * Stick the visible cursor to the mouse pointer.
	 */		
	protected function moveCursor( mouseEvent:MouseEvent ): void
	{
		if ( cursor )
		{
			cursor.x = mouseEvent.localX + cursor.offset_x
			cursor.y = mouseEvent.localY + cursor.offset_y 
		}
	}
	
	/**
	 * Call the interaction method such as CropTool.cropLeftInteraction().
	 * 
	 * @see com.faindu.editImage.crop.CropTool.cropLeftInteraction() 
	 */
	protected function controlMouseMove( event:EditImageEvent ): void 
	{
		if ( interactionMethod != null && editImage.currentControl == this ) 
		{
			interactionMethod( event )
		}
	}
	
	/**
	 * Draw the control.
	 */
	public function draw( event:Event=null ): void 
	{
		position()
	}
	
	/**
	 * Position the control.
	 */
	public function position(): void 
	{
		if (referenceName in editImage.controlsPositions )
		{
			var reference:Point = editImage.controlsPositions[referenceName]
			x = reference.x
			y = reference.y
		}
	}
	
	/**
	 * Reset the position and orientation of the control.
	 */
	public function reset(): void
	{
		var currentMatrix: Matrix = transform.matrix
		transform.matrix = new Matrix( 1, 0, 0, 1, currentMatrix.tx, currentMatrix.ty )
	}

	/**
	 * doc
	 */
	protected function rotateControl( rotationCenter:Point ): void
	{
		// rotate the control and cursor to the same angle as the image.
		var controlsAngle: Number = editImage.rotateTool.deltaAngle
 		if ( controlsAngle != 0 )
		{ 
			var globalMatrix: Matrix = editImage.transform.concatenatedMatrix		
			transform.matrix = parseControlMatrix( controlsAngle, rotationCenter, globalMatrix )
		} 
	}
	
	/**
	 * Parse the matrix necessary for rotating the control.
	 * 
	 * @param controlsAngle angle that the control is rotated. The angle adds up with the angle of previous rotations.
	 * @param rotationCenter This is the position of the control.
	 * @param globalMatrix This is concatenatedMatrix of imageEdit.
	 * @return the matrix for rotating the control.
	 */
	protected function parseControlMatrix( controlsAngle:Number, rotationCenter:Point, globalMatrix:Matrix ): Matrix
	{
		var controlPosition: Point = globalMatrix.transformPoint( rotationCenter )
		
		var translatedGlobalMatrix: Matrix = globalMatrix.clone()
		translatedGlobalMatrix.translate( -controlPosition.x, -controlPosition.y )
		
		var translatedGlobalInvertedMatrix: Matrix = translatedGlobalMatrix.clone()
		translatedGlobalInvertedMatrix.invert()
		
		var controlMatrix: Matrix = transform.matrix
		controlMatrix.concat( translatedGlobalMatrix )
		controlMatrix.rotate( controlsAngle )
		controlMatrix.concat( translatedGlobalInvertedMatrix )
		return controlMatrix
	}
}
}